﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using NavigationBarDemo.Controls.Interfaces;

namespace NavigationBarDemo.Controls.NavigationBar
{
    /// <summary>
    /// 导航栏控件
    /// </summary>
    public class NavigationBar : Control, IButtonGroup<NavigationButton>
    {
        #region 常量
        /// <summary>
        /// 点击一次移动的步长
        /// </summary>
        private const double MoveStep = 100.0;
        /// <summary>
        /// _timer计时器运行时，移动的步长
        /// </summary>
        private const double MoveOneStep = 3.0;
        /// <summary>
        /// _timer2计时器运行时，移动的步长
        /// </summary>
        private const double MoveOneStep2 = 10.0;
        /// <summary>
        /// 向左/向右滚动时，距离最左/最右侧的距离，默认为1.0
        /// </summary>
        private const double ScrollSpace = 1.0;
        #endregion

        #region 变量
        private Grid _rootGrid;
        private Button _btnLeftArrow;
        private Button _btnRightArrow;
        private StackPanel _navigationPanel;
        private ScrollViewer _navigationViewer;

        private double _navButtonWidth;
        private double _moveStep;
        private double _movedStep;

        /// <summary>
        /// 箭头方向
        /// </summary>
        private ArrowDirectEnum _arrowDirect;
        /// <summary>
        /// 鼠标移入时，启动该计时器
        /// </summary>
        private DispatcherTimer _timer;
        /// <summary>
        /// 鼠标点击时，启动该计时器
        /// </summary>
        private DispatcherTimer _timer2;

        /// <summary>
        /// 缓存面板
        /// </summary>
        private readonly StackPanel _cacheStackPanel = new StackPanel();
        /// <summary>
        /// 导航按钮集合
        /// </summary>
        private readonly List<NavigationButton> _navButtonList = new List<NavigationButton>();

        #endregion

        #region 事件
        /// <summary>
        /// 改变按钮组中选中项事件
        /// </summary>
        public event SelectionChangedHandler SelectionChanged;

        #endregion

        #region 构造函数
        public NavigationBar()
        {
            DefaultStyleKey = typeof(NavigationBar);
        }

        #endregion

        #region 重写OnApplyTemplate方法
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _rootGrid = GetTemplateChild("xRootGrid") as Grid;
            _btnLeftArrow = GetTemplateChild("x_btnLeftArrow") as Button;
            _btnRightArrow = GetTemplateChild("x_btnRightArrow") as Button;
            _navigationPanel = GetTemplateChild("xNavigationPanel") as StackPanel;
            _navigationViewer = GetTemplateChild("xNavigationViewer") as ScrollViewer;

            // 将缓存面板中的按钮添加到导航面板中
            if (_navigationPanel != null && _cacheStackPanel.Children.Count > 0)
            {
                for (var i = 0; i < _cacheStackPanel.Children.Count; i++)
                {
                    var temp = _cacheStackPanel.Children[i];
                    _cacheStackPanel.Children.RemoveAt(i--);
                    _navigationPanel.Children.Add(temp);
                }
            }

            if (_rootGrid != null)
            {
                _rootGrid.MouseWheel += OnrootGrid_MouseWheel;
            }
            if (_btnLeftArrow != null)
            {
                _btnLeftArrow.Click += OnbtnArrow_Click;
                _btnLeftArrow.MouseEnter += OnbtnArrow_MouseEnter;
                _btnLeftArrow.MouseLeave += OnbtnArrow_MouseLeave;
            }
            if (_btnRightArrow != null)
            {
                _btnRightArrow.Click += OnbtnArrow_Click;
                _btnRightArrow.MouseEnter += OnbtnArrow_MouseEnter;
                _btnRightArrow.MouseLeave += OnbtnArrow_MouseLeave;
            }
            if (_navigationPanel != null)
            {
                _navigationPanel.SizeChanged += Onnavigation_SizeChanged;
            }
            if (_navigationViewer != null)
            {
                _navigationViewer.SizeChanged += Onnavigation_SizeChanged;
            }

            InitControls();
        }

        #endregion

        #region 初始化控件
        private void InitControls()
        {
            _btnLeftArrow.Visibility = Visibility.Collapsed;
            _btnRightArrow.Visibility = Visibility.Collapsed;

            _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1000.0) };
            _timer.Tick += Ontimer_Tick;

            _timer2 = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(10.0) };
            _timer2.Tick += Ontimer2_Tick;

        }
        #endregion

        #region 计时器
        /// <summary>
        /// 设置计时器的时间间隔
        /// </summary>
        /// <param name="pValue"></param>
        private void SetTimerInterval(double pValue)
        {
            _timer.Interval = TimeSpan.FromMilliseconds(pValue);
        }

        private void Ontimer_Tick(object sender, EventArgs e)
        {
            try
            {
                // 启动后修改时间间隔
                if (_timer.Interval.TotalMilliseconds > 10.0)
                {
                    SetTimerInterval(10.0);
                }
                switch (_arrowDirect)
                {
                    case ArrowDirectEnum.Left:
                        ScrollToLeft();
                        break;
                    case ArrowDirectEnum.Right:
                        ScrollToRight();
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Ontimer2_Tick(object sender, EventArgs e)
        {
            try
            {
                switch (_arrowDirect)
                {
                    case ArrowDirectEnum.Left:
                        ScrollToLeft();
                        break;
                    case ArrowDirectEnum.Right:
                        ScrollToRight();
                        break;
                }
                _movedStep += _moveStep;
                if (_movedStep.CompareTo(MoveStep) >= 0)
                {
                    _timer2.Stop();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region 鼠标事件
        /// <summary>
        /// 鼠标滚动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnrootGrid_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (e.Delta > 0)
            {
                OnbtnArrow_Click("left", null);
            }
            else if (e.Delta < 0)
            {
                OnbtnArrow_Click("right", null);
            }
            e.Handled = true;
        }

        /// <summary>
        /// 改变ScrollViewer、StackPanel大小时触发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Onnavigation_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            int navButtonCount = _navigationPanel.Children.Count;
            double svWidth = _navigationViewer.ActualWidth;
            if ((double.IsNaN(_navButtonWidth) || _navButtonWidth < 1.0) && navButtonCount > 0)
            {
                NavigationButton navButton = _navigationPanel.Children[0] as NavigationButton;
                if (navButton != null)
                {
                    _navButtonWidth = navButton.ActualWidth + navButton.Margin.Left + navButton.Margin.Right;
                }
            }

            if (_navButtonWidth * navButtonCount > svWidth)
            {
                _btnLeftArrow.Visibility = Visibility.Visible;
                _btnRightArrow.Visibility = Visibility.Visible;

                _btnLeftArrow.IsEnabled = true;
                _btnRightArrow.IsEnabled = true;
                double hOffset = _navigationViewer.HorizontalOffset;
                if (hOffset < ScrollSpace)
                {
                    _btnLeftArrow.IsEnabled = false;
                }
                if (_navigationViewer.ScrollableWidth - hOffset < ScrollSpace)
                {
                    _btnRightArrow.IsEnabled = false;
                }
            }
            else
            {
                _btnLeftArrow.Visibility = Visibility.Collapsed;
                _btnRightArrow.Visibility = Visibility.Collapsed;
            }
        }

        /// <summary>
        /// 箭头点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnbtnArrow_Click(object sender, RoutedEventArgs e)
        {
            _timer.Stop();
            _movedStep = 0.0;
            _moveStep = MoveOneStep2;
            if (sender is Button)
            {
                _arrowDirect = ((Button)sender).Tag.ToString()
                    .Equals("left", StringComparison.CurrentCultureIgnoreCase)
                    ? ArrowDirectEnum.Left
                    : ArrowDirectEnum.Right;
            }
            else
            {
                _arrowDirect = sender.ToString()
                    .Equals("left", StringComparison.CurrentCultureIgnoreCase)
                    ? ArrowDirectEnum.Left
                    : ArrowDirectEnum.Right;
            }
            _timer2.Start();
        }

        /// <summary>
        /// 鼠标移入事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnbtnArrow_MouseEnter(object sender, MouseEventArgs e)
        {
            // 计时器启动时的时间间隔
            SetTimerInterval(1000);

            _moveStep = MoveOneStep;
            _arrowDirect = ((Button)sender).Tag.ToString().Equals("left", StringComparison.CurrentCultureIgnoreCase)
                ? ArrowDirectEnum.Left
                : ArrowDirectEnum.Right;
            _timer.Start();
        }

        /// <summary>
        /// 鼠标移出事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnbtnArrow_MouseLeave(object sender, MouseEventArgs e)
        {
            _timer.Stop();
        }
        #endregion

        #region 导航栏滚动操作
        /// <summary>
        /// 向左滚动导航栏
        /// </summary>
        private void ScrollToLeft()
        {
            _btnRightArrow.IsEnabled = true;

            double hOffset = _navigationViewer.HorizontalOffset - _moveStep;
            _navigationViewer.ScrollToHorizontalOffset(hOffset);
            if (hOffset < ScrollSpace)
            {
                _timer.Stop();
                _timer2.Stop();
                _btnLeftArrow.IsEnabled = false;
            }
        }

        /// <summary>
        /// 向右滚动导航栏
        /// </summary>
        private void ScrollToRight()
        {
            _btnLeftArrow.IsEnabled = true;

            double hOffset = _navigationViewer.HorizontalOffset + _moveStep;
            _navigationViewer.ScrollToHorizontalOffset(hOffset);
            if (_navigationViewer.ScrollableWidth - hOffset < ScrollSpace)
            {
                _timer.Stop();
                _timer2.Stop();
                _btnRightArrow.IsEnabled = false;
            }
        }
        #endregion

        #region 实现IButtonGroup接口的属性、方法
        /// <summary>
        /// 返回导航栏按钮的个数
        /// </summary>
        public int Count
        {
            get
            {
                var panel = _navigationPanel ?? _cacheStackPanel;
                return panel.Children.Count;
            }
        }

        /// <summary>
        /// 返回导航栏按钮集合
        /// </summary>
        public List<NavigationButton> Items
        {
            get
            {
                _navButtonList.Clear();
                var panel = _navigationPanel ?? _cacheStackPanel;
                foreach (var navButton in panel.Children.OfType<NavigationButton>())
                {
                    _navButtonList.Add(navButton);
                }
                return _navButtonList;
            }
        }

        /// <summary>
        /// 获取或设置选中项的索引
        /// </summary>
        public int SelectedIndex
        {
            get
            {
                var index = -1;
                var panel = _navigationPanel ?? _cacheStackPanel;
                for (var i = 0; i < panel.Children.Count; i++)
                {
                    var navButton = panel.Children[i] as NavigationButton;
                    if (navButton != null && navButton.IsChecked.GetValueOrDefault())
                    {
                        index = i;
                        break;
                    }
                }
                return index;
            }
            set
            {
                var panel = _navigationPanel ?? _cacheStackPanel;
                for (var i = 0; i < panel.Children.Count; i++)
                {
                    if (i == value)
                    {
                        var navButton = panel.Children[i] as NavigationButton;
                        if (navButton != null)
                        {
                            navButton.IsChecked = true;
                        }
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 获取或设置选中的按钮对象
        /// </summary>
        public NavigationButton SelectedItem
        {
            get
            {
                var panel = _navigationPanel ?? _cacheStackPanel;
                return panel.Children.OfType<NavigationButton>()
                        .FirstOrDefault(navButton => navButton.IsChecked.GetValueOrDefault());
            }
            set
            {
                if (value != null)
                    value.IsChecked = true;
            }
        }

        /// <summary>
        /// 获取选中的按钮集合
        /// </summary>
        public List<NavigationButton> SelectedItems
        {
            get
            {
                var panel = _navigationPanel ?? _cacheStackPanel;
                return panel.Children.OfType<NavigationButton>()
                        .Where(navButton => navButton.IsChecked.GetValueOrDefault())
                        .ToList();
            }
        }

        /// <summary>
        /// 添加导航栏按钮
        /// </summary>
        /// <param name="navButton">需要添加的导航按钮</param>
        public void AddItem(NavigationButton navButton)
        {
            if (navButton == null)
            {
                return;
            }

            // 如果导航面板为null，先添加到缓存面板里，等加载完导航面板再转移其中
            var panel = _navigationPanel ?? _cacheStackPanel;
            panel.Children.Add(navButton);

            navButton.Checked += OnnavButton_Checked;
        }

        void OnnavButton_Checked(object sender, RoutedEventArgs e)
        {
            if (SelectionChanged != null)
                SelectionChanged(this, e);
        }

        /// <summary>
        /// 移除导航栏按钮
        /// </summary>
        /// <param name="pNavButton">需要移除的导航按钮</param>
        public void RemoveItem(NavigationButton pNavButton)
        {
            if (pNavButton == null || _navigationPanel == null)
            {
                return;
            }

            if (_navigationPanel.Children.Contains(pNavButton))
            {
                _navigationPanel.Children.Remove(pNavButton);
            }
        }
        /// <summary>
        /// 移除导航栏按钮
        /// </summary>
        /// <param name="pIndex">按钮索引</param>
        public void RemoveItem(int pIndex)
        {
            if (_navigationPanel == null)
            {
                return;
            }
            if (pIndex > -1 && pIndex < _navigationPanel.Children.Count)
            {
                _navigationPanel.Children.RemoveAt(pIndex);
            }
        }
        /// <summary>
        /// 移除导航栏按钮
        /// </summary>
        /// <param name="pText">按钮上的显示文字</param>
        public void RemoveItem(string pText)
        {
            if (string.IsNullOrWhiteSpace(pText) || _navigationPanel == null)
            {
                return;
            }

            foreach (var navButton
                in _navigationPanel.Children.OfType<NavigationButton>().Where(navButton => navButton.Text.Equals(pText, StringComparison.CurrentCultureIgnoreCase)))
            {
                _navigationPanel.Children.Remove(navButton);
                break;
            }
        }

        /// <summary>
        /// 清空导航按钮
        /// </summary>
        public void ClearItems()
        {
            if (_navigationPanel != null)
            {
                _navigationPanel.Children.Clear();
            }
        }
        #endregion
    }

    public enum ArrowDirectEnum
    {
        Left,
        Right
    }
}
